package hong.jun.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

public class RSASignatureExample {
    private static final Logger logger = LoggerFactory.getLogger(RSASignatureExample.class);

    // 生成RSA密钥对
    public static KeyPair generateKeyPair() throws Exception {
        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
        keyGen.initialize(2048); // 设置密钥长度为2048位
        return keyGen.generateKeyPair();
    }

    // 使用私钥对数据进行签名
    public static String sign(String data, PrivateKey privateKey) throws Exception {
        Signature signature = getSignature();
        signature.initSign(privateKey);
        signature.update(data.getBytes());
        byte[] signedBytes = signature.sign();
        return Base64.getEncoder().encodeToString(signedBytes); // 使用Base64编码签名结果
    }

    // 使用公钥验证签名
    public static boolean verify(String data, String signedData, PublicKey publicKey) throws Exception {
        Signature signature = getSignature();
        signature.initVerify(publicKey);
        signature.update(data.getBytes());
        byte[] signedBytes = Base64.getDecoder().decode(signedData);
        return signature.verify(signedBytes);
    }

    /**
     * 还原私钥
     *
     * @param privateKey 私钥字符串
     * @return PrivateKey 实例
     */
    public static PrivateKey loadPrivateKey(String privateKey) throws Exception {
        byte[] data = Base64.getDecoder().decode(privateKey);
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(data);
        return getKeyFactory().generatePrivate(spec);
    }

    /**
     * 还原公钥
     *
     * @param publicKey 公钥字符串
     * @return PublicKey 实例
     */
    public static PublicKey loadPublicKey(String publicKey) throws Exception {
        byte[] data = Base64.getDecoder().decode(publicKey);
        X509EncodedKeySpec spec = new X509EncodedKeySpec(data);
        return getKeyFactory().generatePublic(spec);
    }

    private static volatile KeyFactory fact;

    private static KeyFactory getKeyFactory() throws NoSuchAlgorithmException {
        if (fact == null) {
            synchronized (KeyFactory.class) {
                if (fact == null) {
                    fact = KeyFactory.getInstance("RSA");
                }
            }
        }
        return fact;
    }

    private static final ThreadLocal<Signature> THREAD_LOCAL_SIGNATURE = ThreadLocal.withInitial(() -> {
        try {
            return Signature.getInstance("SHA256withRSA");
        } catch (Exception e) {
            logger.error("Failed to initialize Signature", e);
            throw new RuntimeException("Failed to initialize Signature instance", e);
        }
    });

    public static Signature getSignature() {
        return THREAD_LOCAL_SIGNATURE.get();
    }
}
